/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief MaCI - Dummy Server interface header.
 * \author Antti Maula <antti.maula@tkk.fi>
 *
 * $Id: DummyServer.hpp,v 1.11 2009-12-08 10:48:27 morsko Exp $
 *
 */
#ifndef _MACI_INTERFACE_DUMMYSERVER_HPP_
#define _MACI_INTERFACE_DUMMYSERVER_HPP_
#include "MaCI.hpp"
#include "DummyData.hpp"
#include "sync.hpp"
#include "thread.hpp"
#include <list>


// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
  class GIMIMessage;
}

namespace MaCI {
  namespace Dummy {
    // Forward declaration.
    class CDummyData;
    class CDummyServer;

    /** Callback interface class for Dummy interface.
     *
     * This interface defines functions which can be used for
     * DummyServer callbacks. These functions are executed (more
     * detail per function basis) as new data arrives, and directly
     * from the context of the receiving thread. <b>Therefore, it is
     * important that the handling function is as simple and fast as
     * possible, as it will block the execution of the receiving
     * thread while executed.</b>
     */
    class CDummyServerCallback
    {
    public:

      CDummyServerCallback() {}
      virtual ~CDummyServerCallback() {}


      /** Handler function for DummyData event.
       *
       * This function is called when the DummyServer receives new
       * data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aData       Constant reference to CDummyData element 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aDummyServer Reference to DummyServer 
       *                        instance which received this event.
       */
      virtual void OnDummyDataEvent(const CDummyData &aData, 
                                    const unsigned int aDataSequence,
                                    CDummyServer &aDummyServer) = 0;
    };


    /** MaCI - Dummy Server interface
     * 
     * This class contains the methods and types for providing
     * the Dummy service in the GIMnet.
     */
    class CDummyServer : public MaCI::CMaCI
                       ,private gim::CSync,
                         private gim::CThread

    {
    public:
      /** Constructor.
       * 
       * Constructor of the DummyServer. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aMaCICtrlServerPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       * used to indicate the instance of devices of same type.
       * @param[in] aDescription User provided description about
       * service. This description will be appended after text
       * 'MaCI-DummyServer; ' in the GIMI service description
       * field.
       * @param[in] aInstanceName Specify Instance name here.
       */
      CDummyServer(MaCICtrl::CMaCICtrlServer *aMaCICtrlServerPtr, 
                   const int aInterfaceMinor,
                   const std::string &aDescription = "",
                   const std::string &aInstanceName = "");


      /** Destructor.
       */
      ~CDummyServer();
 

      /** Send DummyData element
       *
       * This function sends an DummyData container to service
       * subscribers.\n
       *
       * The container to send must contain atleast the following
       * elements:\n
       * \li \c TTimestamp
       * \li \c TDummyEvent
       *
       * @param[in] aDummyData   CDummyData container containing data to send.
       * @return                 Returns a value of type MaCI::EMaCIError.
       */
      MaCI::EMaCIError SendDummyEvent(const CDummyData &aDummyData);

      
      /** Return next incoming command in Queue.
       *
       * This function waits for new commands to arrive for a maximum
       * of 'aTimeout_ms' milliseconds. If a command is received, it
       * is stored to reference 'aData', and the function will return
       * KMaCIOK.
       *
       * @param[out] aData      Reference to CDummyData to be filled with
       *                        received information.
       * @param[out] aSource    Reference to message source information. This
       *                        is required for example for REPLY operations.
       * @param[in] aTimeout_ms Timeout in milliseconds to sleep waiting
       *                        for the operation to complete. If this
       *                        timeout exceeds and no commands are
       *                        received, this function returns KMaCITimeout.
       *
       * @return                \c 'KMaCIOK' on succesfully received command.\n
       *                        \c 'KMaCITimeout' if timeout value exceeded.\n
       *                        \c 'KMaCIInvalidFormat' if the client received
       *                        a message of invalid format. It is safe to ignore this,
       *                        as it is only a notification for the application
       *                        that an invalid message was received. The event
       *                        is returned as it may help tracing down some
       *                        implementation problems.
       */
      MaCI::EMaCIError WaitCommand(CDummyData &aData,
                                   SMessageSource &aSource,
                                   const unsigned int aTimeout_ms);


      /** Send reply to client.
       * 
       * This function sends synchronous reply message to client.
       *
       * @param[in] aData       Reference to CDummyData. This data will be sent to
       *                        client for reply
       * @param[in] aSource     Reference to message source information. This
       *                        is required for example for REPLY operations.
       * @return                'KMaCIOK' when reply message succesfully sent.
       *                        Other errors returned when appropriate.
       *                        (See the MaCI::EMaCIError for description)
       */
      MaCI::EMaCIError SendReply(const CDummyData &aData, 
                                 const SMessageSource &aSource);

      /** Assigns the Dummy server callback function. 
       *
       * This sets a function object for calling a dummy server
       * callback. If this is set, the interface calls the assigned
       * functions immediately when event is available.
       * 
       * \note As the function is run in the context of the receiving
       * thread, user must make sure that the callback function is
       * fast. As if the function executes too long, receiving events
       * is interrupted.
       *
       * @param[in] aDummyServerCallback Pointer to class implementing the interface
       *                                 CDummyServerCallback.
       */
      void SetDummyServerCallback(CDummyServerCallback *aDummyServerCallback) {
        iDummyServerCallback = aDummyServerCallback;
      }
    protected:
      /** Open device.
       *
       * Opens the device, basicly registers device to GIMI.
       *  
       * @return                Returns a value of type MaCI::EMaCIError. 
       *                        
       * \see EMaCIError
       */
      MaCI::EMaCIError DoOpen(void);
      
      
      /** Close device.
       *
       * Closes the device. Closes all GIMI registrations and queues.
       *
       * @return                Returns a value of type EMaCIError.
       *
       * \see EMaCIError
       */
      MaCI::EMaCIError DoClose(void);

    private:

      int ProcessMessage(const CDummyData &aMessage, const SMessageSource &aSource); ///< Process message func.
      int ThreadFunction(const int aThreadNumber); ///< Incoming data handler function
      CDummyData iLastCommand; ///< Last received command NOT handled by thread
      SMessageSource iLastCommandSource;
      unsigned int iCommandSequenceNumber;

      std::string iServiceDescription; ///< User provided service description field.
      unsigned int iDummySequenceNumber;
      CDummyServerCallback *iDummyServerCallback; ///< Pointer to class instance containing callback functions.

      // Override copy & assignment operator privately to disable class copying.
      CDummyServer(const CDummyServer &)
        : CMaCI(NULL, GIMI_PROTOCOL_MACI_DUMMY, 0, ""),
          CSync(1,1),
          CThread(1),
          iLastCommand(),
          iLastCommandSource(),
          iCommandSequenceNumber(0),
          iServiceDescription(""),
          iDummySequenceNumber(0),
          iDummyServerCallback(NULL){}

      CDummyServer &operator=(const CDummyServer &) { return *this; }
    };

  }
}


#endif //_MACI_INTERFACE_DUMMYSERVER_HPP_
